# -*- coding: utf-8 -*-
# @Date：2024/10/2 19:37:20
# @Author：CJiaの青姝
# @FileName：file
# @Editor：PyCharm2024
# @Remark：
import os
from typing import Any, List
from typing_extensions import Self

from auths.models import User
from application.models import AppUploadFile
from ninja import Router, Field, Query, ModelSchema
from ninja.files import UploadedFile
from ninja.pagination import paginate

from backend.settings import BASE_DIR
from utils.cj_ninja import CjFilters, MyPagination
from utils.cj_file import construct_file
from utils.cj_crud import create, delete, batch_delete, update, retrieve, single
from utils.cj_response import SuccessResponse, ErrorResponse

router = Router()


class Filters(CjFilters):
    name: str = Field(None, description="文件名称", alias='name')
    user_id: int = Field(None, description="所属用户id", alias='user_id')

    class Config:
        title = "文件查询参数"


class AppUploadFileSchemaIn(ModelSchema):

    def validate(cls, value: Any) -> Self:
        if value.name == '' or value.name is None:
            return "文件名称不能为空", 400
        # 返回请求数据
        return value, 200

    class Config:
        title = '创建文件参数'
        model = AppUploadFile
        model_fields = ['name', 'remark']


class AppUploadFileSchemaOut(ModelSchema):
    class Config:
        title = '文件对象实例'
        model = AppUploadFile
        model_fields = "__all__"


@router.post("/file/add", response=AppUploadFileSchemaOut, summary="上传文件")
def create_file(request: Any, file: UploadedFile) -> SuccessResponse | ErrorResponse:
    """ 上传文件 """
    # 拼接协议和请求地址
    base_url = f"{request.scheme}://{request.get_host()}/"
    # 调用处理图片方法
    result = construct_file(request, User, file)
    # 没有后缀
    if not result['suffix']:
        return ErrorResponse(msg="请上传正确的格式文件")
    # 若输入的目录不存在, 将自动创建对应的文件目录并将文件上传到该目录中。
    if not os.path.exists(result['path']):
        os.mkdir(result['path'])
    # 文件存在则覆盖
    f = AppUploadFile.objects.filter(name=result["name"], suffix=result["suffix"], user_id=request.user_id).first()
    if f:
        # 删除文件记录
        delete(AppUploadFile, f.id)
    # 保存文件
    try:
        # 判断当前文件是否存在
        with open(result['path'] + result['name'] + f".{result['suffix']}", "wb") as f:
            f.write(file.read())
        # 完整路径
        result['path'] = result['path'] + result['name'] + f".{result['suffix']}"
        result['url'] = base_url + result['url'] + result['name'] + f".{result['suffix']}"
        result['baseDir'] = str(BASE_DIR)
        # 保存文件
        result = create(request, AppUploadFile, result)
        # 返回数据
        return SuccessResponse(data=result, msg="上传成功")
    except FileExistsError as e:
        return ErrorResponse(code=400, msg=e)


@router.post("/file/batch/add", response=List[AppUploadFileSchemaOut], summary="批量上传文件")
def batch_create_file(request: Any, file: List[UploadedFile]) -> SuccessResponse | ErrorResponse:
    """ 批量上传文件 """
    # 拼接协议和请求地址
    base_url = f"{request.scheme}://{request.get_host()}/"
    # 完成列表
    upload = []
    # 循环上传文件
    for f_item in file:
        # 调用处理图片方法
        result = construct_file(request, User, f_item)
        # 若输入的目录不存在, 将自动创建对应的文件目录并将文件上传到该目录中。
        if not os.path.exists(result['path']):
            os.mkdir(result['path'])
        # 文件存在则覆盖
        f = AppUploadFile.objects.filter(name=result["name"], suffix=result["suffix"], user_id=request.user_id).first()
        if f:
            # 删除文件记录
            delete(AppUploadFile, f.id)
        # 保存文件
        try:
            if result['suffix']:
                # 判断当前文件是否存在
                with open(result['path'] + result['name'] + f".{result['suffix']}", "wb") as f:
                    f.write(f_item.read())
                # 完整路径
                result['path'] = result['path'] + result['name'] + f".{result['suffix']}"
                result['url'] = base_url + result['url'] + result['name'] + f".{result['suffix']}"
                result['baseDir'] = str(BASE_DIR)
                # 保存文件
                upload.append(create(request, AppUploadFile, result))
        except FileExistsError as e:
            return ErrorResponse(code=400, msg=e)
    # 返回数据
    return SuccessResponse(data=upload, msg="上传成功")


@router.delete("/file/del/{uuid}", response=AppUploadFileSchemaOut, summary="删除文件")
def delete_app_file(request: Any, uuid: int) -> SuccessResponse | ErrorResponse:
    """ 删除文件 """
    # 调用删除方法
    result, code = delete(AppUploadFile, uuid)
    if code != 200:
        return ErrorResponse(code=code, msg=result)
    # 记录删除异常
    error = ""
    try:
        # 删除文件
        os.remove(os.path.abspath(result['fileDir']))
    except FileExistsError:
        # 删除异常
        error = FileExistsError
        # 防止数据库存在文件信息，但是目录文件已被删除
        print("文件删除失败：", FileExistsError)
    finally:
        # 返回结果
        return SuccessResponse(data=result, msg=f"删除成功[{error}]")


@router.post("/file/batch/del", summary="批量删除文件")
def batch_delete_file(request, ids: List[int]) -> SuccessResponse | ErrorResponse:
    """ 批量删除文件 """
    # 循环删除当前存在的文件
    for pk in ids:
        # 文件对象
        file = AppUploadFile.objects.filter(id=pk).first()
        if file:
            try:
                # 存在删除
                os.remove(os.path.abspath(file.fileDir))
            except FileExistsError:
                # 防止数据库存在文件信息，但是目录文件已被删除
                print("文件删除失败：", FileExistsError)
    # 调用批量删除方法
    result = batch_delete(request, AppUploadFile, ids)
    # 返回结果
    return SuccessResponse(msg=f"成功删除{result[0]}条数据, 失败{result[1]}条数据")


@router.put("/file/update/{uuid}", response=AppUploadFileSchemaOut, summary="更新文件")
def update_app_file(request: Any, uuid: int, data: AppUploadFileSchemaIn) -> SuccessResponse | ErrorResponse:
    """ 更新文件 """
    message, code = data.validate(data)
    if code == 400:
        return ErrorResponse(msg=message)
    # 文件对象
    file = {
        "name": "",
        "fileDir": "",
        "path": "",
        "url": "",
        "remark": "",
    }
    # 调用根据id获取指定对象方法
    result, code = single(request, AppUploadFile, [], uuid)
    # 重命名
    file["name"] = message.name + "." + result.suffix  # 防止前端改后缀
    file["path"] = result.path[:result.path.rfind('/') + 1] + file["name"]
    file["fileDir"] = result.fileDir[:result.fileDir.rfind('/') + 1] + file["name"]
    file["url"] = result.url[:result.url.rfind('/') + 1] + file["name"]
    file["remark"] = message.remark
    # 修改文件名称
    os.rename(os.path.abspath(result.fileDir), os.path.abspath(file["fileDir"]))
    # 调用修改方法
    result = update(request, AppUploadFile, file, uuid)
    # 返回结果
    return SuccessResponse(data=result, msg="更新成功")


@router.get("/file/listPage", response=List[AppUploadFileSchemaOut], summary="获取分页文件列表")
@paginate(MyPagination)
def list_page_app_file(request: Any, filters: Filters = Query(...)) -> SuccessResponse | ErrorResponse:
    """ 获取分页文件列表 """
    # 取当前用户所属的应用
    filters.user_id = request.user_id
    # 调用列表通用方法
    result = retrieve(request, AppUploadFile, [], filters)
    # 返回结果
    return result


@router.get("/file/listAll", response=List[AppUploadFileSchemaOut], summary="获取文件详情所有列表")
def list_all_app_file(request: Any, filters: Filters = Query(...)) -> SuccessResponse | ErrorResponse:
    """ 获取文件详情所有列表 """
    # 取当前用户所属的应用
    filters.user_id = request.user_id
    # 调用列表通用方法
    result = retrieve(request, AppUploadFile, [], filters)
    # 返回结果
    return result


@router.get("/file/getById/{uuid}", response=AppUploadFileSchemaOut, summary="获取文件详情")
def get_app_file(request: Any, uuid: int) -> SuccessResponse | ErrorResponse:
    """ 获取文件详情 """
    # 调用根据id获取指定对象方法
    result, code = single(request, AppUploadFile, [], uuid)
    if code != 200:
        return ErrorResponse(code=code, msg=result)
    # 返回结果
    return result
